package com.woniuxy.config;

import com.woniuxy.filter.AccessFilter;
import com.woniuxy.mapper.PawnResourceMapper;
import com.woniuxy.service.Impl.LoginErrorHandler;
import com.woniuxy.service.Impl.LoginSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;

@Configuration
//@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private LoginErrorHandler handler = new LoginErrorHandler();
    @Resource
    private StringRedisTemplate srt;
    @Resource
    private PawnResourceMapper mapper;

    public UrlBasedCorsConfigurationSource getCors() {
        //1. 添加 CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //放行哪些原始域
        config.addAllowedOrigin("*");
        //是否发送 Cookie
        config.setAllowCredentials(true);
        //放行哪些请求方式
        config.addAllowedMethod("*");
        //放行哪些原始请求头部信息
        config.addAllowedHeader("*");
        //暴露哪些头部信息
        config.addExposedHeader("*");
        //2. 添加映射路径
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", config);
        //3. 返回新的CorsFilter
        return corsConfigurationSource;
    }

    @Bean
    public PasswordEncoder createPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //configure(HttpSecurity)允许基于选择匹配在资源级配置基于网络的安全性。
    //    Security的认证策略, 每个模块配置使用and结尾。
    //    authorizeRequests()配置路径拦截，表明路径访问所对应的权限，角色，认证信息。
    //    formLogin()对应表单认证相关的配置
    //    logout()对应了注销相关的配置
    //    httpBasic()可以配置basic登录
    //    disable()取消默认验证

    //    authenticated()做验证
    //    csrf方法：SpringSecurity提供的跨站请求伪造防护功能，当我们继承WebSecurityConfigurerAdapter的时候，会默认自动开启csrf方法，不需要我们额外写一下

    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问（非remember-me下自动登录）
     * hasAnyAuthority     |   如果有参数，参数表示权限，则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数，参数表示角色，则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数，参数表示权限，则其权限可以访问
     * hasIpAddress        |   如果有参数，参数表示IP地址，如果用户IP和参数匹配，则可以访问
     * hasRole             |   如果有参数，参数表示角色，则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //自定义拦截器
        http.addFilterAfter(new AccessFilter(handler, srt, mapper), FilterSecurityInterceptor.class)
                //关闭基础的认证功能
                .httpBasic().disable()
                .csrf().disable()
                //配置自定义的认证拦截方式
                .authorizeRequests()
                //匹配到某些Url资源进行放行
                /*       匹配资源字符串可以用通配符来进行指定例如：
                         “*//**//**”、"/login/**","/user/*.ajax"
         */
                .antMatchers( "/file/upload","/v2/api-docs", "/swagger-resources/**", "/webjars/**/*", "/swagger-ui.html"
                        , "/user-table/noneLogin.do").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/user-table/noneLogin.do")
                .loginProcessingUrl("/login")
                .successHandler(new LoginSuccessHandler())
                .failureHandler(handler)
                .and().cors().configurationSource(getCors());
    }
}
